package com.gorillalogic.scrummonkey.test {
	import com.gorillalogic.scrummonkey.dms.Iteration;
	import com.gorillalogic.scrummonkey.dms.IterationService;
	import com.gorillalogic.scrummonkey.dms.Project;
	import com.gorillalogic.scrummonkey.dms.ProjectService;
	import com.gorillalogic.scrummonkey.dms.Release;
	import com.gorillalogic.scrummonkey.dms.ReleaseService;
	
	import mx.collections.ArrayCollection;
	
	import org.flexunit.Assert;
	import org.hamcrest.Matcher;
	import org.hamcrest.assertThat;
	import org.hamcrest.collection.hasItems;

	public class IterationTest extends BaseTest{

		/**
		 * Create a whole bunch of I under R under P and then verify success.
		 */
		[Test(async,order=1)]
		public function create():void {
			var p:Project = new Project('iterationtest-proj1','desc-proj1');

			var r1:Release = new Release('rel1');
			var r2:Release = new Release('rel2');
			var r3:Release = new Release('rel3');

			var i1:Iteration = new Iteration('it1');
			var i2:Iteration = new Iteration('it2');
			var i3:Iteration = new Iteration('it3');
			var i4:Iteration = new Iteration('it4');
			var i5:Iteration = new Iteration('it5');
			var i6:Iteration = new Iteration('it6');
			var i7:Iteration = new Iteration('it7');
			var i8:Iteration = new Iteration('it8');
			var i9:Iteration = new Iteration('it9');
			var i10:Iteration = new Iteration('it10');
			var i11:Iteration = new Iteration('it11');
			var i12:Iteration = new Iteration('it12');
			var i13:Iteration = new Iteration('it13');
			var i14:Iteration = new Iteration('it14');
			var i15:Iteration = new Iteration('it15');
			var i16:Iteration = new Iteration('it16');
			var i17:Iteration = new Iteration('it17');
			var i18:Iteration = new Iteration('it18');
			var i19:Iteration = new Iteration('it19');
			var i20:Iteration = new Iteration('it20');
			var i21:Iteration = new Iteration('it21');
			var i22:Iteration = new Iteration('it22');
			var i23:Iteration = new Iteration('it23');
			var i24:Iteration = new Iteration('it24');
			var i25:Iteration = new Iteration('it25');
			var i26:Iteration = new Iteration('it26');
			var i27:Iteration = new Iteration('it27');
			var i28:Iteration = new Iteration('it28');
			var i29:Iteration = new Iteration('it29');
			var i30:Iteration = new Iteration('it30');

			//wireup project & release
			p.releases.addItem(r1);
			p.releases.addItem(r2);
			p.releases.addItem(r3);

			r1.project = p;
			r2.project = p;
			r3.project = p;

			//wireup release & iteration
			r1.iterations.addItem(i1);
			r1.iterations.addItem(i2);
			r1.iterations.addItem(i3);
			r1.iterations.addItem(i4);
			r1.iterations.addItem(i5);
			r1.iterations.addItem(i6);
			r1.iterations.addItem(i7);
			r1.iterations.addItem(i8);
			r1.iterations.addItem(i9);
			r1.iterations.addItem(i10);

			r2.iterations.addItem(i11);
			r2.iterations.addItem(i12);
			r2.iterations.addItem(i13);
			r2.iterations.addItem(i14);
			r2.iterations.addItem(i15);
			r2.iterations.addItem(i16);
			r2.iterations.addItem(i17);
			r2.iterations.addItem(i18);
			r2.iterations.addItem(i19);
			r2.iterations.addItem(i20);

			r3.iterations.addItem(i21);
			r3.iterations.addItem(i22);
			r3.iterations.addItem(i23);
			r3.iterations.addItem(i24);
			r3.iterations.addItem(i25);
			r3.iterations.addItem(i26);
			r3.iterations.addItem(i27);
			r3.iterations.addItem(i28);
			r3.iterations.addItem(i29);
			r3.iterations.addItem(i30);

			i1.release = r1;
			i2.release = r1;
			i3.release = r1;
			i4.release = r1;
			i5.release = r1;
			i6.release = r1;
			i7.release = r1;
			i8.release = r1;
			i9.release = r1;
			i10.release = r1;

			i11.release = r2;
			i12.release = r2;
			i13.release = r2;
			i14.release = r2;
			i15.release = r2;
			i16.release = r2;
			i17.release = r2;
			i18.release = r2;
			i19.release = r2;
			i20.release = r2;

			i21.release = r3;
			i22.release = r3;
			i23.release = r3;
			i24.release = r3;
			i25.release = r3;
			i26.release = r3;
			i27.release = r3;
			i28.release = r3;
			i29.release = r3;
			i30.release = r3;

			callAndThenOrFault(ProjectService.service.createProject(p), create2, null, 50000);
		}

		private function create2(data:Object, passThroughData:Object):void {
			callAndThenOrFault(ProjectService.service.getByName('iterationtest-proj1'), create3);
		}

		private function create3(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'iterationtest-proj1', project.name);
			Assert.assertEquals('Bad project description', 'desc-proj1', project.description);

			//verify releases
			Assert.assertEquals('Bad number of releases', 3, project.releases.length);

			var releaseNames:Array = project.releases.toArray().map(
				function (r:Release, idx:int, items:Array):String {
					return r.name;
				});

			assertThat('Bad release names', releaseNames, hasItems('rel1','rel2','rel3'));

			callAndThenOrFault(ReleaseService.service.getByName('rel1'), create4, null, 5000,
				{releaseName:'rel1', iterationMatcher:hasItems('it1','it2','it3','it4','it5','it6','it7','it8','it9','it10')});

			callAndThenOrFault(ReleaseService.service.getByName('rel2'), create4, null, 5000,
				{releaseName:'rel2', iterationMatcher:hasItems('it11','it12','it13','it14','it15','it16','it17','it18','it19','it20')});

			callAndThenOrFault(ReleaseService.service.getByName('rel3'), create4, null, 5000,
				{releaseName:'rel3', iterationMatcher:hasItems('it21','it22','it23','it24','it25','it26','it27','it28','it29','it30')});
		}

		private function create4(data:Object, passThroughData:Object):void {
			var releaseName:String = passThroughData['releaseName'];
			var iterationMatcher:Matcher = passThroughData['iterationMatcher'] as Matcher;

			var release:Release = (data.result as ArrayCollection).getItemAt(0) as Release;
			Assert.assertEquals('Bad release name', releaseName, release.name);
			Assert.assertEquals('Bad project name', 'iterationtest-proj1', release.project.name);
			Assert.assertNull('Bad release description', release.description);

			//verify iterations
			Assert.assertEquals('Bad number of iterations', 10, release.iterations.length);

			var iterationNames:Array = release.iterations.toArray().map(
				function (i:Iteration, idx:int, items:Array):String {
					return i.name;
				});

			assertThat('Bad iteration names', iterationNames, iterationMatcher);
			
			var iteration:Iteration = release.iterations.getItemAt(0) as Iteration;
			Assert.assertNull('Bad iteration description', release.description);
			Assert.assertEquals("Bad iteration's release name", release.name, iteration.release.name);
		}


		/**
		 * Cleanup P, 3 R's, and all 30 I's
		 */
		[Test(async,order=2)]
		public function cleanup():void {
			callAndThenOrFault(ProjectService.service.getByName('iterationtest-proj1'), cleanup2);
		}

		private function cleanup2(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'iterationtest-proj1', project.name);

			callAndThenOrFault(ProjectService.service.deleteProject(project), cleanup3);
		}

		private function cleanup3(data:Object, passThroughData:Object):void {
			callAndThenOrFault(ProjectService.service.getByName('iterationtest-proj1'), cleanup4);
			callAndThenOrFault(ReleaseService.service.getByName('rel1'), cleanup4);
			callAndThenOrFault(ReleaseService.service.getByName('rel2'), cleanup4);
			callAndThenOrFault(ReleaseService.service.getByName('rel3'), cleanup4);
			callAndThenOrFault(IterationService.service.getByName('it1'), cleanup4);
			callAndThenOrFault(IterationService.service.getByName('it15'), cleanup4);
			callAndThenOrFault(IterationService.service.getByName('it30'), cleanup4);
		}

		private function cleanup4(data:Object, passThroughData:Object):void {
			var entities:ArrayCollection = data.result as ArrayCollection;
			Assert.assertEquals('Cleanup failed', 0, entities.length);
		}
	}
}